﻿//TradeSerializer.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Algo.Storages
{
	using System;
	using System.Collections.Generic;
	using System.IO;
	using System.Linq;

	using Ecng.Common;
	using Ecng.Collections;
	using Ecng.Serialization;

	using StockSharp.BusinessEntities;

	class TradeMetaInfo : MetaInfo<TradeMetaInfo>
	{
		public TradeMetaInfo(DateTime date)
			: base(date)
		{
			FirstId = -1;
		}

		public long FirstId { get; set; }
		public long PrevId { get; set; }

		public override void Write(Stream s)
		{
			base.Write(s);

			s.Write(FirstId);
			s.Write(PrevId);
			s.Write(FirstPrice);
			s.Write(LastPrice);

			if (Version < MarketDataVersions.Version43)
				return;

			s.Write(FirstNonSystemPrice);
			s.Write(PrevNonSystemPrice);
		}

		public override void Read(Stream s)
		{
			base.Read(s);

			FirstId = s.Read<long>();
			PrevId = s.Read<long>();
			FirstPrice = s.Read<decimal>();
			LastPrice = s.Read<decimal>();

			if (Version < MarketDataVersions.Version43)
				return;

			FirstNonSystemPrice = s.Read<decimal>();
			PrevNonSystemPrice = s.Read<decimal>();
		}

		protected override void CopyFrom(TradeMetaInfo src)
		{
			base.CopyFrom(src);

			FirstId = src.FirstId;
			PrevId = src.PrevId;
			FirstPrice = src.FirstPrice;
			LastPrice = src.LastPrice;
			FirstNonSystemPrice = src.FirstNonSystemPrice;
			PrevNonSystemPrice = src.PrevNonSystemPrice;
		}
	}

	class TradeSerializer : MarketDataSerializer<Trade, TradeMetaInfo>
	{
		public TradeSerializer(Security security)
			: base(security, 50)
		{
		}

		protected override void OnSave(List<bool> bits, IEnumerable<Trade> trades, TradeMetaInfo metaInfo)
		{
			if (metaInfo.IsEmpty() && !trades.IsEmpty())
				metaInfo.FirstId = metaInfo.PrevId = trades.First().Id;

			bits.SerializeInt(trades.Count());

			foreach (var trade in trades)
			{
				// сделки для индексов имеют нулевой номер
				if (trade.Id < 0)
					throw new ArgumentOutOfRangeException("trades", trade.Id, "Неправильный номер сделки.");

				if (trade.Price <= 0)
					throw new ArgumentOutOfRangeException("trades", trade.Price, "Неправильная цена сделки {0}.".Put(trade.Id));

				// pyhta4og.
				// http://stocksharp.com/forum/yaf_postsm6450_Oshibka-pri-importie-instrumientov-s-Finama.aspx#post6450

				if (trade.Volume < 0)
					throw new ArgumentOutOfRangeException("trades", trade.Volume, "Неправильный объем сделки {0}.".Put(trade.Id));

				metaInfo.PrevId = bits.SerializeId(trade.Id, metaInfo.PrevId);

				bits.SerializeVolume(trade.Volume);
				bits.SerializePriceEx(trade.Price, metaInfo, Security);
				bits.SerializeTradeDirection(trade.OrderDirection);

				metaInfo.LastTime = bits.SerializeTime(trade.Time, metaInfo.LastTime, "сделки");

				if (metaInfo.Version >= MarketDataVersions.Version40)
				{
					bits.SerializeLong(trade.Latency.Ticks);

					if (metaInfo.Version >= MarketDataVersions.Version42)
					{
						bits.Add(trade.IsSystem);

						if (!trade.IsSystem)
							bits.SerializeInt(trade.Status);

						bits.SerializeVolume(trade.OpenInterest);
					}
				}
			}
		}

		public override Trade MoveNext(MarketDataEnumerator<Trade, TradeMetaInfo> enumerator)
		{
			var reader = enumerator.Reader;
			var metaInfo = enumerator.MetaInfo;

			metaInfo.FirstId += reader.ReadLong();
			var volume = reader.DeserializeVolume();
			var price = reader.DeserializePriceEx(metaInfo);

			var orderDirection = reader.Read() ? (reader.Read() ? OrderDirections.Buy : OrderDirections.Sell) : (OrderDirections?)null;

			metaInfo.FirstTime = reader.ReadTime(enumerator.Date, metaInfo.FirstTime);

			var trade = new Trade
			{
				Security = Security,
				Id = metaInfo.FirstId,
				Volume = volume,
				OrderDirection = orderDirection,
				Price = price,
				Time = metaInfo.FirstTime,
			};

			if (metaInfo.Version >= MarketDataVersions.Version40)
			{
				trade.Latency = reader.ReadLong().To<TimeSpan>();

				if (metaInfo.Version >= MarketDataVersions.Version42)
				{
					trade.IsSystem = reader.Read();

					if (!trade.IsSystem)
						trade.Status = reader.ReadInt();

					trade.OpenInterest = reader.DeserializeVolume();
				}
			}
			
			return trade;
		}
	}
}